package org.jim.server.helper.cs;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.json.JSONUtil;
import com.huiyun.project.common.core.constant.SecurityConstants;
import com.huiyun.project.common.core.util.fn.FunctionUtils;
import com.huiyun.project.im.consts.ImCsSessionConst;
import com.huiyun.project.im.server.client.feign.RemoteCsSessionService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jim.core.ImConst;
import org.jim.core.cache.redis.JedisTemplate;
import org.jim.core.cache.redis.RedisCacheManager;
import org.jim.core.helper.cs.ICsSessionHelper;
import org.jim.core.packets.cs.session.vo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * @FileName:
 * @Description:
 * @Author linjie
 * @Date 2020/7/309:43 AM
 * @Version 4.0.0
 */
@Component
@Slf4j
public class CsSessionHelperImpl implements ICsSessionHelper {
    @Autowired
    private RemoteCsSessionService remoteSessionService;

    /**
     * 检查会话  目前只有客户才会有
     *
     * @param checkReq
     * @return
     */
    @Override
    public JimCsCreateSessionResp check(JimCsCheckSessionReq checkReq) {
        JimCsCreateSessionResp resp = null;
        try {
            //此处没有检查技能组,是避免一个人有多个技能组,产生多个会话
            JimCsSession req = getSessionByRedis(checkReq.getSessionId(), checkReq.getUserId(), checkReq.getCsTenantId(),"user");
            Assert.notNull(req);
            Assert.isTrue(checkReq.getCsTenantId().equals(req.getCsTenantId()));
            Assert.isTrue(checkReq.getUserId().equals(req.getUserId()));
            resp = new JimCsCreateSessionResp();
            resp.setSessionId(req.getId());
            resp.setCsTenantLogo(req.getCsTenantLogo());
            resp.setCsNick(req.getCsNick());
            resp.setCsId(req.getCsId());
            resp.setCsTenantCate(req.getCsTenantCate());
            resp.setCsTenantId(req.getCsTenantId());
            resp.setUserId(req.getUserId());
            resp.setUserNick(req.getUserNick());
            resp.setUserAvatar("");
        } catch (Exception ex) {
            log.error("check cs session error {} {}", ex.getMessage(), JSONUtil.toJsonStr(checkReq));
        }
        return resp;
    }

    /**
     * 从缓存里面获取 session
     *
     * @param sessionId  sessionid
     * @param userId     用户id
     * @param csTenantId 租户id
     * @return
     */
    public JimCsSession getSessionByRedis(String sessionId, String userId, String csTenantId,String type) {
        JimCsSession session = null;
        try {
            if (StringUtils.isNotBlank(sessionId)) {//如果sessionId存在
                session = JedisTemplate.me().get(getKey(sessionId), JimCsSession.class);
                if (session != null) {
                    return session;
                }
            }
            //没查询到 根据userId 和租户id查询
            Set<String> keys = JedisTemplate.me().sorSetRangeByScore(getPageKey(type,userId), Double.MIN_VALUE, Double.MAX_VALUE);
            for (String s : keys) {
                session = JedisTemplate.me().get(getKey(s), JimCsSession.class);
                if (session.getCsTenantId().equals(csTenantId)) {
                    return session;
                }
            }
        } catch (Exception e) {

        }


        return session;

    }

    @Override
    public JimCsSession get(String sessionId) {
        JimCsSession session = null;
        try {
            session = JedisTemplate.me().get(getKey(sessionId), JimCsSession.class);
            if (session != null) {
                return session;
            }
            JimCsGetSessionResp resp = FunctionUtils.getOkData(remoteSessionService.getSessionById(sessionId, SecurityConstants.FROM_IN));
            if (resp == null) {
                session = new JimCsSession();
                BeanUtil.copyProperties(resp, session);
                return session;
            }
            return session;
        } catch (Exception ex) {
            log.error("get  session error {} {}", ex.getMessage());
        }
        return session;
    }


    @Override
    public JimCsCreateSessionResp create(JimCsCreateSessionReq req) {
        JimCsCreateSessionResp csCreateSessionResp = null;
        try {
            //2.存储redis (可以优化pipline+trancaction)
           /* Pipeline p1 = jedis.pipelined();
            p1.multi();//开启事务
            p1.incr(key);
            System.out.println("Request incr");
            p1.incr(key);
            System.out.println("Request incr");
            Response<List<Object>> txresult= p1.exec();//提交事务
            p1.sync();//关闭pipeline
            //结束pipeline，并开始从相应中获得数据
            List<Object> responses = txresult.get();
            */
            //1.持久化
            JimCsSession resp = FunctionUtils.getOkData(remoteSessionService.createSession(req, SecurityConstants.FROM_IN));
            //2.session存储到redis
            JedisTemplate.me().set(getKey(resp.getId()), resp);
            /**
             * 用户会话列表(用户有哪些会话)
             */
            JedisTemplate.me().sortSetPush(getPageKey(ImConst.USER, req.getUserId()), resp.getSort(), resp.getId());
            /**
             * 客服会话列表(客服有哪些会话)
             */
            JedisTemplate.me().sortSetPush(getPageKey(ImConst.CS, req.getCsId()), resp.getSort(), resp.getId());

            csCreateSessionResp = new JimCsCreateSessionResp();
            csCreateSessionResp.setSessionId(resp.getId());
            csCreateSessionResp.setCsTenantLogo(resp.getCsTenantLogo());
            csCreateSessionResp.setCsNick(resp.getCsNick());
            csCreateSessionResp.setCsId(resp.getCsId());
            csCreateSessionResp.setCsTenantCate(resp.getCsTenantCate());
            csCreateSessionResp.setCsTenantId(resp.getCsTenantId());
            csCreateSessionResp.setUserId(resp.getUserId());
            csCreateSessionResp.setUserNick(resp.getUserNick());
            csCreateSessionResp.setUserAvatar("");
        } catch (Exception ex) {
            log.error("session create error:{} ", ex.getMessage());
        }
        return csCreateSessionResp;
    }

    /**
     * 客服结束会话
     *
     * @param csId
     * @param sessionId
     * @return
     */
    @Override
    public Boolean csEnd(String csId, String sessionId) {
        //1.删除缓存会话(会话列表清除掉,session 缓存修改,远程session也修改)
        try {
            JimCsSession req = get(sessionId);
            if (req != null && (req.getUserId().equals(csId) || req.getCsTenantId().equals(csId))) {
                //移除列表
                JedisTemplate.me().listRemove(getPageKey(ImConst.CS,csId), 0, sessionId);
            }
            //修改客服端的删除状态,并且将状态设置为结束
            return FunctionUtils.getOkData(remoteSessionService.end(csId, sessionId, SecurityConstants.FROM_IN));
        } catch (Exception e) {
            log.error("cs failed to end session {} " + e.getMessage());
        }

        return false;
    }

    /**
     * 客服清理已经结束的会话 ,重新查询一次数据库,并且更新缓存
     * 通常会用到的情况 用户那边结束了
     *
     * @param csId
     * @return
     */
    @Override
    public Boolean csDelEnd(String csId) {
        //FunctionUtils.getOkData(remoteSessionService.getSessionList());
        return null;
    }


    /**
     * 用户结束会话
     *
     * @param from
     * @param sessionId
     * @return
     */
    @Override
    public Boolean userDel(String from, String sessionId) {
        JimCsSession req = RedisCacheManager.getCache(ImConst.SESSION_CS).get(sessionId, JimCsSession.class);
        if (req != null && (req.getUserId().equals(from) || req.getCsTenantId().equals(from))) {
            req.setStatus(ImCsSessionConst.STATUS.END.getValue());
            RedisCacheManager.getCache(ImConst.SESSION_CS).set(sessionId, req);
        }
        //2.远程将会话设置为结束状态
        return FunctionUtils.getOkData(remoteSessionService.end(from, sessionId, SecurityConstants.FROM_IN));
    }

    @Override
    public JimCsSessionConfigResp getConfig(String tenantId) {
        return FunctionUtils.getOkData(remoteSessionService.getConfig(tenantId, SecurityConstants.FROM_IN));
    }


    /**
     * 查询会话列表
     *
     * @return
     */
    public List<JimCsGetSessionResp> getList(JimCsGetSessionReq jimGetSessionReq) {
        try {
            //先从缓存查
            List<JimCsSession> list = new ArrayList<>();
            String user="";
            if(ImConst.USER_OPERATE.equals(jimGetSessionReq.getOperateType())){
                user="user";
            }else if(ImConst.CS_OPERATE.equals(jimGetSessionReq.getOperateType())){
                user="cs";
            }
            Set<String> kes = JedisTemplate.me().sorSetRangeByScore(getPageKey(user,jimGetSessionReq.getUid()), 0L, 10L, jimGetSessionReq.getPageNum() - 1, jimGetSessionReq.getPageSize());
            for (String s : kes) {
                list.add(JedisTemplate.me().get(getKey(s), JimCsSession.class));
            }
            if (CollectionUtil.isNotEmpty(list)) {
                // 转换对象
                List<JimCsGetSessionResp> getSessionList = new ArrayList<>();
                JimCsGetSessionResp resp;
                for (JimCsSession csSession : list) {
                    resp = new JimCsGetSessionResp();
                    BeanUtil.copyProperties(csSession, resp);
                    resp.setSessionId(csSession.getId());
                    getSessionList.add(resp);
                }
                return getSessionList;
            } else {
                //如果没有则从数据库查
                return FunctionUtils.getOkData(remoteSessionService.getSessionList(jimGetSessionReq, SecurityConstants.FROM_IN));
            }
        } catch (Exception e) {

        }


        return null;
    }


    /**
     * operateType 1.用户刷新会话 2.客服刷新会话
     * 1.更新会话时间 2.更新最后一条消息内容 3.更新未读消息数量 4.更新用户或者客服发消息时间
     *
     * @param sessionId   会话Id
     * @param refreshTime 刷新时间
     * @param lastMsg     最后一条消息
     */
    public void refresh(String sessionId, Long refreshTime, String lastMsg, Integer operateType) {

    }

    /**
     * readAll
     * fuid读取sessionId的消息,fuid 可用于校验
     */
    public void readAll(String from, String sessionId, Integer operateType) {

    }


}


